#pragma once

#include <compl/candy.h>


#define __MAP_UNSIGNED(type, y)		type : y, unsigned type : y

/* 比特位操作 */
/* FIXME: 手动实现 COMPCERT不支持 ffs */
#define __FFS(x)			__builtin_ffs((unsigned int)x)
#define __FFSL(x)			__builtin_ffsl((unsigned long)x)
#define __FFSLL(x)			__builtin_ffsll((unsigned long long)x)
#define __FFSG(x)			\
	_Generic((x), __MAP_UNSIGNED(int, __FFS(x)), __MAP_UNSIGNED(long, __FFSL(x)), __MAP_UNSIGNED(long long, __FFSLL(x)))
	
#define __CLZ(x)			__builtin_clz((unsigned int)x)
#define __CLZL(x)			__builtin_clzl((unsigned long)x)
#define __CLZLL(x)			__builtin_clzll((unsigned long long)x)
#define __CLZG(x)			\
	_Generic((x), int: __CLZ(x), unsigned long: __CLZL(x), long:	__CLZL(x), long long: __CLZLL(x))

#define __PARITY(x)			__builtin_parity((unsigned int)x)
#define __PARITYL(x) 			__builtin_parityl((unsigned long)x)
#define __PARITYLL(x)			__builtin_parityll((unsigned long long)x)
#define __PARITYG(x)			\
	_Generic((x), unsigned int: __PARITY(x), unsigned long:__PARITYL(x), unsigned long long: __PARITYLL(x))


#define __POPCOUNT(x)			__builtin_popcount((unsigned int)x)
#define __POPCOUNTL(x)			__builtin_popcountl((unsigned long)x)
#define __POPCOUNTLL(x)			__builtin_popcountll((unsigned long long)x)
#define __POPCOUNTG(x)			\
	_Generic((x), unsigned int: __POPCOUNT(x), unsigned long:__POPCOUNTL(x), unsigned long long: __POPCOUNTLL(x))


#define ffs_generic(x)			(TIF_ELSE(sizeof(x) == sizeof(int), __FFS(x),	\
	(TIF_ELSE(sizeof(x) == sizeof(long), __FFSL(x),					\
		(TIF_ELSE(sizeof(x) == sizeof(long long), __FFSLL(x),			\
			TCOND_UNREACHABLE)						\
			)								\
			)								\
		)									\
	)										\
)

#define clz_generic(x)			(TIF_ELSE(sizeof(x) == sizeof(int), __CLZ(x),	\
	(TIF_ELSE(sizeof(x) == sizeof(long), __CLZL(x),					\
		(TIF_ELSE(sizeof(x) == sizeof(long long), __CLZLL(x),			\
			TCOND_UNREACHABLE)						\
			) 								\
			) 								\
		)									\
	)										\
)


#define fls_generic(x)												\
	(TIF_ELSE(sizeof(x) == sizeof(int), (int)(__SIZEOF_INT__*__CHAR_BIT__) - __CLZ(x),			\
		(TIF_ELSE(sizeof(x) == sizeof(long), (int)(__SIZEOF_LONG__*__CHAR_BIT__) - __CLZL(x),		\
		(TIF_ELSE(sizeof(x) == sizeof(long long), (int)(__SIZEOF_LONG_LONG__*__CHAR_BIT__) - __CLZLL(x),\
			TCOND_UNREACHABLE)									\
				) 										\
			)											\
		)												\
	)													\
)

#define __FLSG(x)			\
	_Generic((x), __MAP_UNSIGNED(int, (__SIZEOF_INT__*__CHAR_BIT__) - __CLZ(x)),\
	__MAP_UNSIGNED(long, (__SIZEOF_LONG__*__CHAR_BIT__) - __CLZL(x)),\
	__MAP_UNSIGNED(long long,  (__SIZEOF_LONG_LONG__*__CHAR_BIT__) - __CLZLL(x)))

#define parity_generic(x)			(TIF_ELSE(sizeof(x) == sizeof(int), __PARITY(x),		\
	(TIF_ELSE(sizeof(x) == sizeof(long), __PARITYL(x), 							\
		(TIF_ELSE(sizeof(x) == sizeof(long long), __PARITYLL(x),					\
			TCOND_UNREACHABLE)									\
			) 											\
			) 											\
		) 												\
	)													\
)

#define popcount_generic(x)		(TIF_ELSE(sizeof(x) == sizeof(int), __POPCOUNT(x),			\
	(TIF_ELSE(sizeof(x) == sizeof(long), __POPCOUNTL(x),							\
		(TIF_ELSE(sizeof(x) == sizeof(long long), __POPCOUNTLL(x),					\
		TCOND_UNREACHABLE)										\
		)												\
		)												\
	)													\
)														\
)



/* 字节序操作 */
// #define __BYTE_ORDER			(__BYTE_ORDER__)
/* 交换字节序 */
#define bswap(x)			TIF_ELSE(sizeof(x) == sizeof(uint16_t), __builtin_bswap16((uint16_t)x),	\
	TIF_ELSE(sizeof(x) == sizeof(uint32_t), __builtin_bswap32((uint32_t)x),					\
		TIF_ELSE(sizeof(x) == sizeof(uint64_t), __builtin_bswap64((uint64_t)x),				\
			TIF_ELSE(sizeof(x) == sizeof(uint128_t),  __builtin_bswap128((uint128_t)x),		\
			TCOND_UNREACHABLE) 									\
				)										\
			)											\
		)
/* 泛型的字节序转换 */
#define hton_generic(x)			TIF_ELSE(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, bswap(x),		\
						TIF_ELSE(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__, x, (void) 0))
#define ntoh_generic(x)			TIF_ELSE(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, bswap(x),		\
						TIF_ELSE(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__, x, (void) 0))

